import os
import time
import json
import subprocess
import platform
import webbrowser
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
import pandas as pd
import matplotlib.pyplot as plt

# 多端兼容性测试脚本

class CompatibilityTester:
    def __init__(self, base_url, test_pages, viewport_sizes):
        self.base_url = base_url
        self.test_pages = test_pages
        self.viewport_sizes = viewport_sizes
        self.results = []
        self.screenshots_dir = "compatibility_results/screenshots"
        
        # 创建结果目录
        os.makedirs(self.screenshots_dir, exist_ok=True)
    
    def setup_driver(self, viewport_width, viewport_height):
        """设置WebDriver并配置视口大小"""
        chrome_options = Options()
        chrome_options.add_argument("--headless")  # 无头模式
        chrome_options.add_argument("--no-sandbox")
        chrome_options.add_argument("--disable-dev-shm-usage")
        
        driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options)
        driver.set_window_size(viewport_width, viewport_height)
        return driver
    
    def test_page(self, page, viewport_size):
        """测试特定页面在特定视口大小下的兼容性"""
        viewport_width, viewport_height = viewport_size
        device_name = f"{viewport_width}x{viewport_height}"
        
        print(f"测试页面 {page} 在 {device_name} 视口下的兼容性...")
        
        driver = self.setup_driver(viewport_width, viewport_height)
        url = f"{self.base_url}{page}"
        
        try:
            start_time = time.time()
            driver.get(url)
            load_time = time.time() - start_time
            
            # 等待页面加载完成
            time.sleep(2)
            
            # 截图
            screenshot_path = f"{self.screenshots_dir}/{page.replace('/', '_')}_{device_name}.png"
            driver.save_screenshot(screenshot_path)
            
            # 检查页面元素是否正确显示
            visible_elements = len(driver.find_elements(By.XPATH, "//*[not(self::script) and not(self::style) and not(self::meta) and not(self::link) and not(self::noscript)]"))
            
            # 检查是否有水平滚动条
            has_horizontal_scroll = driver.execute_script(
                "return document.documentElement.scrollWidth > document.documentElement.clientWidth"
            )
            
            # 检查是否有重叠元素
            overlapping_elements = driver.execute_script("""
                const elements = document.querySelectorAll('*');
                let count = 0;
                
                for (let i = 0; i < elements.length; i++) {
                    const el1 = elements[i];
                    const rect1 = el1.getBoundingClientRect();
                    
                    if (rect1.width === 0 || rect1.height === 0) continue;
                    
                    for (let j = i + 1; j < elements.length; j++) {
                        const el2 = elements[j];
                        const rect2 = el2.getBoundingClientRect();
                        
                        if (rect2.width === 0 || rect2.height === 0) continue;
                        
                        // 检查两个元素是否重叠
                        if (!(rect1.right < rect2.left || 
                              rect1.left > rect2.right || 
                              rect1.bottom < rect2.top || 
                              rect1.top > rect2.bottom)) {
                            // 如果元素是父子关系，则跳过
                            if (!el1.contains(el2) && !el2.contains(el1)) {
                                count++;
                            }
                        }
                    }
                }
                
                return count;
            """)
            
            # 运行Lighthouse测试
            lighthouse_score = self.run_lighthouse(url) if viewport_width >= 768 else None
            
            result = {
                "page": page,
                "viewport": device_name,
                "load_time": load_time,
                "visible_elements": visible_elements,
                "has_horizontal_scroll": has_horizontal_scroll,
                "overlapping_elements": overlapping_elements,
                "screenshot": screenshot_path,
                "lighthouse_score": lighthouse_score,
                "status": "Pass" if not has_horizontal_scroll and overlapping_elements < 10 else "Fail"
            }
            
            self.results.append(result)
            print(f"  结果: {result['status']}, 加载时间: {load_time:.2f}秒")
            
        except Exception as e:
            print(f"  测试失败: {str(e)}")
            self.results.append({
                "page": page,
                "viewport": device_name,
                "error": str(e),
                "status": "Error"
            })
        finally:
            driver.quit()
    
    def run_lighthouse(self, url):
        """运行Lighthouse测试并返回性能分数"""
        try:
            # 检查是否安装了Lighthouse
            subprocess.run(["lighthouse", "--version"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            
            # 运行Lighthouse测试
            output_path = f"compatibility_results/lighthouse_{url.replace('://', '_').replace('/', '_')}.json"
            subprocess.run([
                "lighthouse", 
                url, 
                "--output=json", 
                f"--output-path={output_path}",
                "--chrome-flags='--headless'",
                "--only-categories=performance,accessibility"
            ], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            
            # 解析结果
            with open(output_path, 'r') as f:
                data = json.load(f)
                performance_score = data['categories']['performance']['score'] * 100
                accessibility_score = data['categories']['accessibility']['score'] * 100
                return {
                    "performance": performance_score,
                    "accessibility": accessibility_score
                }
        except Exception as e:
            print(f"Lighthouse测试失败: {str(e)}")
            return None
    
    def run_tests(self):
        """运行所有测试"""
        print(f"开始兼容性测试: {len(self.test_pages)}个页面, {len(self.viewport_sizes)}种视口大小")
        
        for page in self.test_pages:
            for viewport_size in self.viewport_sizes:
                self.test_page(page, viewport_size)
        
        self.analyze_results()
    
    def analyze_results(self):
        """分析测试结果"""
        print("\n兼容性测试结果:")
        print("-" * 50)
        
        # 按页面和视口大小统计通过率
        pass_count = sum(1 for r in self.results if r.get('status') == 'Pass')
        fail_count = sum(1 for r in self.results if r.get('status') == 'Fail')
        error_count = sum(1 for r in self.results if r.get('status') == 'Error')
        total_count = len(self.results)
        
        print(f"总测试数: {total_count}")
        print(f"通过数: {pass_count} ({pass_count/total_count*100:.2f}%)")
        print(f"失败数: {fail_count} ({fail_count/total_count*100:.2f}%)")
        print(f"错误数: {error_count} ({error_count/total_count*100:.2f}%)")
        
        # 按页面统计
        df = pd.DataFrame(self.results)
        if not df.empty and 'page' in df.columns and 'status' in df.columns:
            page_stats = df.groupby('page')['status'].value_counts().unstack().fillna(0)
            print("\n按页面统计:")
            print(page_stats)
            
            # 按视口大小统计
            if 'viewport' in df.columns:
                viewport_stats = df.groupby('viewport')['status'].value_counts().unstack().fillna(0)
                print("\n按视口大小统计:")
                print(viewport_stats)
        
        print("-" * 50)
    
    def generate_report(self, filename="compatibility_test_report.md"):
        """生成测试报告"""
        with open(filename, 'w') as f:
            f.write("# 多端兼容性测试报告\n\n")
            f.write(f"- 基础URL: {self.base_url}\n")
            f.write(f"- 测试页面数: {len(self.test_pages)}\n")
            f.write(f"- 测试视口大小: {len(self.viewport_sizes)}\n\n")
            
            # 总体结果
            pass_count = sum(1 for r in self.results if r.get('status') == 'Pass')
            fail_count = sum(1 for r in self.results if r.get('status') == 'Fail')
            error_count = sum(1 for r in self.results if r.get('status') == 'Error')
            total_count = len(self.results)
            
            f.write("## 测试结果摘要\n\n")
            f.write(f"- 总测试数: {total_count}\n")
            f.write(f"- 通过数: {pass_count} ({pass_count/total_count*100:.2f}%)\n")
            f.write(f"- 失败数: {fail_count} ({fail_count/total_count*100:.2f}%)\n")
            f.write(f"- 错误数: {error_count} ({error_count/total_count*100:.2f}%)\n\n")
            
            # 按页面统计
            df = pd.DataFrame(self.results)
            if not df.empty and 'page' in df.columns and 'status' in df.columns:
                f.write("## 按页面统计\n\n")
                page_stats = df.groupby('page')['status'].value_counts().unstack().fillna(0)
                f.write(page_stats.to_markdown() + "\n\n")
                
                # 生成页面通过率图表
                plt.figure(figsize=(10, 6))
                pass_rates = []
                pages = []
                
                for page in self.test_pages:
                    page_results = [r for r in self.results if r.get('page') == page]
                    if page_results:
                        page_pass = sum(1 for r in page_results if r.get('status') == 'Pass')
                        page_total = len(page_results)
                        pass_rate = page_pass / page_total * 100
                        pass_rates.append(pass_rate)
                        pages.append(page)
                
                plt.bar(pages, pass_rates, color='green')
                plt.title('页面通过率')
                plt.xlabel('页面')
                plt.ylabel('通过率 (%)')
                plt.xticks(rotation=45, ha='right')
                plt.tight_layout()
                plt.savefig('compatibility_results/page_pass_rates.png')
                plt.close()
                
                f.write("![页面通过率](compatibility_results/page_pass_rates.png)\n\n")
                
                # 按视口大小统计
                if 'viewport' in df.columns:
                    f.write("## 按视口大小统计\n\n")
                    viewport_stats = df.groupby('viewport')['status'].value_counts().unstack().fillna(0)
                    f.write(viewport_stats.to_markdown() + "\n\n")
                    
                    # 生成视口大小通过率图表
                    plt.figure(figsize=(10, 6))
                    viewport_pass_rates = []
                    viewports = []
                    
                    for viewport in [f"{w}x{h}" for w, h in self.viewport_sizes]:
                        viewport_results = [r for r in self.results if r.get('viewport') == viewport]
                        if viewport_results:
                            viewport_pass = sum(1 for r in viewport_results if r.get('status') == 'Pass')
                            viewport_total = len(viewport_results)
                            pass_rate = viewport_pass / viewport_total * 100
                            viewport_pass_rates.append(pass_rate)
                            viewports.append(viewport)
                    
                    plt.bar(viewports, viewport_pass_rates, color='blue')
                    plt.title('视口大小通过率')
                    plt.xlabel('视口大小')
                    plt.ylabel('通过率 (%)')
                    plt.xticks(rotation=45, ha='right')
                    plt.tight_layout()
                    plt.savefig('compatibility_results/viewport_pass_rates.png')
                    plt.close()
                    
                    f.write("![视口大小通过率](compatibility_results/viewport_pass_rates.png)\n\n")
            
            # 详细结果
            f.write("## 详细测试结果\n\n")
            
            for page in self.test_pages:
                f.write(f"### 页面: {page}\n\n")
                
                page_results = [r for r in self.results if r.get('page') == page]
                if not page_results:
                    f.write("无测试结果\n\n")
                    continue
                
                f.write("| 视口大小 | 状态 | 加载时间 | 水平滚动 | 重叠元素 | Lighthouse性能 | Lighthouse可访问性 |\n")
                f.write("|----------|------|----------|----------|----------|----------------|------------------|\n")
                
                for result in page_results:
                    status = result.get('status', 'Unknown')
                    viewport = result.get('viewport', 'Unknown')
                    load_time = f"{result.get('load_time', 0):.2f}秒" if 'load_time' in result else 'N/A'
                    has_scroll = "是" if result.get('has_horizontal_scroll', False) else "否"
                    overlapping = result.get('overlapping_elements', 'N/A')
                    
                    lighthouse = result.get('lighthouse_score', None)
                    perf_score = f"{lighthouse['performance']:.0f}" if lighthouse and 'performance' in lighthouse else 'N/A'
                    access_score = f"{lighthouse['accessibility']:.0f}" if lighthouse and 'accessibility' in lighthouse else 'N/A'
                    
                    f.write(f"| {viewport} | {status} | {load_time} | {has_scroll} | {overlapping} | {perf_score} | {access_score} |\n")
                
                f.write("\n截图:\n\n")
                
                for result in page_results:
                    if 'screenshot' in result:
                        screenshot = result['screenshot']
                        viewport = result['viewport']
                        f.write(f"**{viewport}**:\n\n")
                        f.write(f"![{page} - {viewport}]({screenshot})\n\n")
            
            # 问题和建议
            f.write("## 发现的问题和建议\n\n")
            
            # 水平滚动问题
            horizontal_scroll_pages = [r for r in self.results if r.get('has_horizontal_scroll', False)]
            if horizontal_scroll_pages:
                f.write("### 存在水平滚动问题的页面\n\n")
                for result in horizontal_scroll_pages:
                    f.write(f"- {result['page']} 在 {result['viewport']} 视口下存在水平滚动\n")
                
                f.write("\n建议:\n")
                f.write("- 检查页面宽度设置，确保使用响应式单位（如%、vw、rem）而非固定像素\n")
                f.write("- 使用媒体查询调整小屏幕上的元素大小和布局\n")
                f.write("- 确保图片和表格等宽元素设置了最大宽度\n\n")
            
            # 元素重叠问题
            overlapping_pages = [r for r in self.results if r.get('overlapping_elements', 0) > 10]
            if overlapping_pages:
                f.write("### 存在严重元素重叠问题的页面\n\n")
                for result in overlapping_pages:
                    f.write(f"- {result['page']} 在 {result['viewport']} 视口下有 {result['overlapping_elements']} 个重叠元素\n")
                
                f.write("\n建议:\n")
                f.write("- 检查元素定位方式，避免绝对定位导致的重叠\n")
                f.write("- 调整响应式布局中的元素排列方式\n")
                f.write("- 使用Flexbox或Grid布局提高布局稳定性\n\n")
            
            # Lighthouse性能问题
            low_perf_pages = [r for r in self.results if r.get('lighthouse_score') and r['lighthouse_score'].get('performance', 100) < 70]
            if low_perf_pages:
                f.write("### Lighthouse性能得分低的页面\n\n")
                for result in low_perf_pages:
                    f.write(f"- {result['page']} 在 {result['viewport']} 视口下性能得分为 {result['lighthouse_score']['performance']:.0f}\n")
                
                f.write("\n建议:\n")
                f.write("- 优化图片大小和格式\n")
                f.write("- 减少JavaScript和CSS文件大小\n")
                f.write("- 实施懒加载技术\n")
                f.write("- 优化关键渲染路径\n\n")
            
            # 可访问性问题
            low_access_pages = [r for r in self.results if r.get('lighthouse_score') and r['lighthouse_score'].get('accessibility', 100) < 70]
            if low_access_pages:
                f.write("### Lighthouse可访问性得分低的页面\n\n")
                for result in low_access_pages:
                    f.write(f"- {result['page']} 在 {result['viewport']} 视口下可访问性得分为 {result['lighthouse_score']['accessibility']:.0f}\n")
                
                f.write("\n建议:\n")
                f.write("- 添加适当的ARIA标签\n")
                f.write("- 确保颜色对比度符合WCAG标准\n")
                f.write("- 添加图片的替代文本\n")
                f.write("- 确保表单元素有正确的标签\n\n")
            
            # 总体建议
            f.write("## 总体建议\n\n")
            f.write("1. **实施完全响应式设计**：确保所有页面在各种设备上都能正常显示\n")
            f.write("2. **优化移动体验**：为移动用户提供简化的界面和触摸友好的交互\n")
            f.write("3. **提高页面加载速度**：优化资源加载，减少首次内容绘制时间\n")
            f.write("4. **增强可访问性**：遵循WCAG 2.1标准，确保所有用户都能使用网站\n")
            f.write("5. **持续测试**：在开发过程中定期进行兼容性测试，及早发现问题\n")
        
        print(f"兼容性测试报告已生成: {filename}")

# 示例使用
if __name__ == "__main__":
    # 这里使用模拟的URL和页面，实际使用时替换为真实的URL
    base_url = "http://localhost:3000"
    test_pages = [
        "/",
        "/login",
        "/register",
        "/bazi",
        "/character",
        "/fengshui",
        "/tools",
        "/profile",
        "/wallet",
        "/vip"
    ]
    
    # 定义要测试的视口大小（宽x高）
    viewport_sizes = [
        (320, 568),  # iPhone SE
        (375, 667),  # iPhone 8
        (414, 896),  # iPhone XR
        (768, 1024), # iPad
        (1024, 768), # 横向iPad
        (1280, 800), # 小型笔记本
        (1920, 1080) # 桌面显示器
    ]
    
    # 运行测试
    tester = CompatibilityTester(base_url, test_pages, viewport_sizes)
    tester.run_tests()
    tester.generate_report()
